package serveur;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.UUID;

import DTO.AnnonceDTO;
import DTO.Capsule;
import DTO.ResumeAnnonceDTO;
import DTO.VendeurDTO;



/**
 * 
 * Le serveur.
 * 
 * @author Valentin Brémond
 *
 * @version 1.0
 *
 */
public class Serveur
{
	/**
	 * Le port du serveur.
	 */
	private static final short port = 8123;
	
	/**
	 * Le socket du serveur.
	 */
	private ServerSocket server = null;
	
	/**
	 * Le socket du client.
	 */
	private Socket client = null;
	
	/**
	 * L'UUID associé à chaque client.
	 */
	private UUID id_client = null;
	
	
	
	// MÉTHODES
	
	
	
	/**
	 * Méthode principale.
	 * 
	 * @param args
	 */
	public static void main(String[] args)
	{
		new Serveur().launch();
	}
	
	
	
	/**
	 * Méthode lancée au démarrage du serveur.
	 */
	public void launch()
	{
		try
		{
			server = new ServerSocket(port);
			
			System.out.println("[INFO] Serveur lancé sur le port " + port + ". En attente de clients...");
			
			// On écoute le réseau en permanence ; dès qu'un client se connecte, on lance un thread
			while(true)
			{
				client = server.accept();
				id_client = UUID.randomUUID();
				
				// Lancement du thread prenant en charge le client
				new DiscussionClient(client, id_client).start();
				
				System.out.println("[INFO] Client " + id_client + " connecté, prêt pour la prochaine connexion.");
			}
		}
		catch (IOException ioE)
		{ 
			ioE.printStackTrace();
		}
		catch(IllegalThreadStateException itsE)
		{
			itsE.printStackTrace();
		}
		 
		System.out.println ("Server arrêté.");
	}

	
	
	
	
	/**
	 * 
	 * Classe prenant en charge un client.
	 * 
	 * @author Valentin Brémond
	 *
	 * @version 1.0
	 * 
	 */
	private class DiscussionClient extends Thread
	{
		/**
		 * Le socket du client.
		 */
		private Socket client;
		
		/**
		 * L'ID du client.
		 */
		private UUID id_client;
		
		/**
		 * Le buffer d'entrée.
		 */
		private ObjectInputStream in = null;
		
		/**
		 * Le buffer de sortie.
		 */
		private ObjectOutputStream out = null;
		
		/**
		 * Booléen permettant d'arrêter le thread.
		 */
		private boolean running = true;
		
		
		
		/**
		 * Constructeur par valeurs.
		 * 
		 * @param client Le socket du client.
		 * @param id_client L'ID du client.
		 */
		private DiscussionClient(Socket client, UUID id_client)
		{	
			this.client = client;
			this.id_client = id_client;
			
			try
			{
				this.out = new ObjectOutputStream(new BufferedOutputStream(this.client.getOutputStream()));
				
				// On flushe un coup pour que l'input du client puisse se lancer
				this.out.flush();
				
				this.in = new ObjectInputStream(new BufferedInputStream(this.client.getInputStream()));
			}
			catch(IOException ioE)
			{
				ioE.printStackTrace();
			}
		}
		
		
		
		/**
		 * Méthode lancée en tant que thread.
		 */
		public void run()
		{
			System.out.println("[INFO] Démarrage du thread pour le client " + id_client + "...");
			
			Capsule entree = null;
			String methode = null;
			
			try
			{
				while(running)
				{
					System.out.println("[INFO] En attente de la capsule du client " + id_client + "...");
					
					entree = (Capsule) in.readObject();
					
					methode = entree.getMethode();
					
					if(!entree.isRequete())
					{
						System.err.println("[INFO] Erreur : requête attendue, une réponse a été reçue.");
					}
					else
					{
						if(methode.equals("ajouterAnnonce"))
						{
							System.out.println("[INFO] Traitement : ajouter annonce.");
							
							int retour = AnnonceDAO.getInstance().ajouterAnnonce(entree.getAnnonce());
							
							Capsule capsule = new Capsule();
							capsule.setReponseAjouterAnnonce(retour);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("modifierAnnonce"))
						{
							System.out.println("[INFO] Traitement : modifier annonce.");
							
							int retour = AnnonceDAO.getInstance().modifierAnnonce(entree.getId(), entree.getAnnonce());
							
							Capsule capsule = new Capsule();
							capsule.setReponseModifierAnnonce(retour);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("supprimerAnnonce"))
						{
							System.out.println("[INFO] Traitement : supprimer annonce.");
							
							boolean fait = AnnonceDAO.getInstance().supprimerAnnonce(entree.getId());
							
							Capsule capsule = new Capsule();
							capsule.setReponseSupprimerAnnonce(fait);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("recupererAnnonce"))
						{
							System.out.println("[INFO] Traitement : récupérer annonce.");
							
							AnnonceDTO annonce = AnnonceDAO.getInstance().recupererAnnonce(entree.getId());
							
							Capsule capsule = new Capsule();
							capsule.setReponseRecupererAnnonce(annonce);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("recupererToutesAnnonces"))
						{
							System.out.println("[INFO] Traitement : récupérer toutes les annonces.");
							
							List<ResumeAnnonceDTO> liste = AnnonceDAO.getInstance().recupererToutesAnnonces();
							
							Capsule capsule = new Capsule();
							capsule.setReponseRecupererToutesAnnonces(liste);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("recupererAnnoncesVendeur"))
						{
							System.out.println("[INFO] Traitement : récupérer toutes les annonces d'un vendeur.");
							
							List<ResumeAnnonceDTO> liste = AnnonceDAO.getInstance().recupererAnnoncesVendeur(entree.getId());
							
							Capsule capsule = new Capsule();
							capsule.setReponseRecupererAnnoncesVendeur(liste);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("ajouterVendeur"))
						{
							System.out.println("[INFO] Traitement : ajouter vendeur.");
							
							int retour = VendeurDAO.getInstance().ajouterVendeur(entree.getVendeur());
							
							Capsule capsule = new Capsule();
							capsule.setReponseAjouterVendeur(retour);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("modifierVendeur"))
						{
							System.out.println("[INFO] Traitement : modifier vendeur.");
							
							int retour = VendeurDAO.getInstance().modifierVendeur(entree.getId(), entree.getVendeur());
							
							Capsule capsule = new Capsule();
							capsule.setReponseModifierVendeur(retour);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("supprimerVendeur"))
						{
							System.out.println("[INFO] Traitement : supprimer vendeur.");
							
							boolean fait = VendeurDAO.getInstance().supprimerVendeur(entree.getId());
							
							Capsule capsule = new Capsule();
							capsule.setReponseSupprimerVendeur(fait);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("recupererVendeur"))
						{
							System.out.println("[INFO] Traitement : récupérer vendeur.");
							
							VendeurDTO vendeur = VendeurDAO.getInstance().recupererVendeur(entree.getId());
							
							Capsule capsule = new Capsule();
							capsule.setReponseRecupererVendeur(vendeur);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("connexionVendeur"))
						{
							System.out.println("[INFO] Traitement : connecter un vendeur.");
							
							int id = VendeurDAO.getInstance().connexionVendeur(entree.getLogin(), entree.getMotDePasse());
							
							Capsule capsule = new Capsule();
							capsule.setReponseConnexionVendeur(id);
							
							out.writeObject(capsule);
							out.flush();
						}
						else if(methode.equals("quitter"))
						{
							System.out.println("[INFO] Le client demande la déconnexion.");
							
							running = false;
						}
						else
						{
							System.err.println("[INFO] Traitement impossible : la Capsule est malformée.");
						}
					}
				}
			}
			catch(IOException ioE)
			{
				ioE.printStackTrace();
			}
			catch(ClassNotFoundException cnfE)
			{
				cnfE.printStackTrace();
			}
			finally
			{
				try
				{
					if(out != null)
					{
						out.close();
					}
					if(in != null)
					{
						in.close();	
					}
					if(client != null)
					{
						client.close();	
					}
				}
				catch(IOException ioE)
				{
					ioE.printStackTrace();
				}
			}
			
			System.out.println("[STOP] Fin du thread pour le client " + id_client + ".");
		}
	}
	
}
